﻿using System;
using System.Xml;
using Notoric.Model.Internal;
using Notoric.Model.Packaging;

namespace Notoric.Model.Elements
{
    /// <summary>
    /// Implements an image section.
    /// </summary>
    public class ImageSectionElement : SectionElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="ImageSectionElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="PageElement"/>
        /// </para>
        /// <para>
        /// The page element that directly owns this section.
        /// </para>
        /// </param>
        /// <param name="interiorCreator">
        /// <para>
        /// Type: <see cref="SectionInteriorCreator"/>
        /// </para>
        /// <para>
        /// A factory method that will create the section interior.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="packagePart"/> or <paramref name="owner"/> or <paramref name="interiorCreator"/> is <see langword="null"/>.
        /// </exception>
        internal ImageSectionElement(XmlPackagePart packagePart, PageElement owner, SectionInteriorCreator interiorCreator)
            : base(packagePart, owner, interiorCreator)
        {
            Interior.CreateContent(null);
        }

        /// <summary>
        /// Creates a new <see cref="ImageSectionElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ModelElement"/>
        /// </para>
        /// <para>
        /// The page element that directly owns this section.
        /// </para>
        /// </param>
        /// <param name="element">
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// An XML element that represents this object.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="packagePart"/>, <paramref name="owner"/> or <paramref name="element"/> is <see langword="null"/>.
        /// </exception>
        internal ImageSectionElement(XmlPackagePart packagePart, ModelElement owner, XmlElement element)
            : base(packagePart, owner, element)
        {
            imageAttribute = element.Attributes[PackageVocabulary.ImageFileAttribute];

            Interior = ModelElement.LoadElement<SectionInteriorElement>(packagePart, this, (XmlElement)InteriorElement.FirstChild);
        }

        #endregion

        #region SectionElement Members

        /// <inheritdoc/>
        protected override XmlElement CreateObjectElementCore(XmlDocument document)
        {
            var element = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.ImageSectionElementName,
                PackageVocabulary.PackageNamespaceUri
                );

            imageAttribute = document.CreateAttribute(PackageVocabulary.ImageFileAttribute);
            element.Attributes.Append(imageAttribute);

            return element;
        }

        /// <inheritdoc/>
        internal override bool HandleBorderRequest(Internal.SectionBorderRequest request)
        {
            if (request is Internal.ImageSectionBorderRequest)
                return Interior.HandleBorderRequest(request);

            return false;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the resource file that holds the image
        /// that is visualized in this section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Uri"/>
        /// </para>
        /// <para>
        /// The URI of the <see cref="ResourcePart"/> that holds
        /// the data of the image that is visualized in this section.
        /// </para>
        /// </value>
        public Uri ImageFile
        {
            get { return new Uri(imageAttribute.Value, UriKind.Relative); }
            set
            {
                imageAttribute.Value = value.ToString();
                RaisePropertyChanged("ImageFile");
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the XML attribute that holds the reference to the image resource
        /// set to this section.
        /// </summary>
        private XmlAttribute imageAttribute;

        #endregion
    }

    /// <summary>
    /// Implements a default interior for an <see cref="ImageSectionElement"/>.
    /// </summary>
    public class DefaultImageSectionInterior : SectionInteriorElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="DefaultImageSectionInterior"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ImageSectionElement"/>
        /// </para>
        /// <para>
        /// The page element that directly owns this section.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="packagePart"/> or <paramref name="owner"/> is <see langword="null"/>.
        /// </exception>
        private DefaultImageSectionInterior(XmlPackagePart packagePart, ImageSectionElement owner)
            : base(packagePart, owner)
        {
        }

        /// <summary>
        /// Creates a new <see cref="DefaultImageSectionInterior"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ModelElement"/>
        /// </para>
        /// <para>
        /// The page element that directly owns this section.
        /// </para>
        /// </param>
        /// <param name="element">
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// An XML element that represents this object.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="packagePart"/>, <paramref name="owner"/> or <paramref name="element"/> is <see langword="null"/>.
        /// </exception>
        internal DefaultImageSectionInterior(XmlPackagePart packagePart, ModelElement owner, XmlElement element)
            : base(packagePart, owner, element)
        {
        }

        #endregion

        #region SectionInteriorElement Members

        /// <inheritdoc/>
        protected override XmlElement CreateObjectElementCore(XmlDocument document)
        {
            var element = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                PackageVocabulary.DefaultImageSectionInteriorElementName,
                PackageVocabulary.PackageNamespaceUri
                );

            return element;
        }

        /// <inheritdoc/>
        protected override void CreateContentCore(object parameter)
        {
            
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Implements the <see cref="SectionInteriorCreator"/> delegate.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns the element.
        /// </para>
        /// </param>
        /// <param name="section">
        /// <para>
        /// Type: <see cref="SectionElement"/>
        /// </para>
        /// <para>
        /// The section that directly owns the element.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="SectionInteriorElement"/>
        /// </para>
        /// <para>
        /// The created section interior element.
        /// </para>
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="packagePart"/> or <paramref name="section"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The <paramref name="section"/> is not an <see cref="ImageSectionElement"/> instance.
        /// </exception>
        public static SectionInteriorElement CreateInstance(XmlPackagePart packagePart, SectionElement section)
        {
            if (packagePart == null)
                throw new ArgumentNullException("packagePart");
            if (section == null)
                throw new ArgumentNullException("section");
            if (!(section is ImageSectionElement))
                throw new ArgumentException("This interior can only be part of an image section!", "section");

            return new DefaultImageSectionInterior(packagePart, section as ImageSectionElement);
        }

        #endregion
    }

}
